package jmind.core.jdbc;

import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import jmind.core.util.DataUtil;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;

/**
 * BeanPropertyRowMapper 直接解析bean
 * @author weibo-xie
 * 2011-12-20
 * @param <E>
 */
public abstract class BeanJdbc<E> extends BaseJdbc {
    private static final String GETS = "select * from %s where %s=? limit ?,?";

    private volatile RowMapper<E> rm = null;
    private volatile SimpleJdbcInsert jdbcInsert;

    public String tableName = getType().getSimpleName().toLowerCase();

    @SuppressWarnings("unchecked")
    public Class<E> getType() {
        ParameterizedType p = (ParameterizedType) getClass().getGenericSuperclass();
        return (Class<E>) p.getActualTypeArguments()[0];
    }

    public RowMapper<E> getRowMapper() {
        if (rm == null) {
            rm = new BeanPropertyRowMapper<E>(getType());
        }
        return rm;
    }

    //    public RowMapper<E> getRowMapper(Class<E> cal) {
    //        if (rm == null)
    //            rm = new BeanPropertyRowMapper<E>(cal);
    //        return rm;
    //    }

    /**
     * 只有tableName 是 pojo的小写形式才满足条件
     * 2013-7-3 
     * @return
     */
    public SimpleJdbcInsert getSimpleJdbcInsert() {
        if (jdbcInsert == null) {
            jdbcInsert = new SimpleJdbcInsert(getJdbc(MASTER_SOURCE).getDataSource()).withTableName(tableName);// usingGeneratedKeyColumns("id");
        }
        return jdbcInsert;
    }

    public int insert(E obj) {
        return super.insert(getSimpleJdbcInsert(), obj);
    }

    public int delete(String keyName, Object key) {
        return super.delete(tableName, keyName, key);
    }

    public E findOne(int source, String sql, Object... args) {
        try {
            return getJdbc(source).queryForObject(sql, getRowMapper(), args);
        } catch (DataAccessException e) {
            return null;
        }

    }

    public List<E> find(int source, String sql, Object... args) {
        List<E> list = getJdbc(source).query(sql, getRowMapper(), args);
        return list;
    }

    /**
     * select * from user where id in (:ids) ;
     * 必须是SimpleJdbcTemplate
     * @param source
     * @param sql
     * @param args
     * @return
     */
    public List<E> sFind(int source, String sql, SqlParameterSource args) {
        //   final MapSqlParameterSource parameters = new MapSqlParameterSource();
        //   parameters.addValue("ids", ids);

        NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(getJdbc(source).getDataSource());
        List<E> list = template.query(sql, args, getRowMapper());
        return list;
    }

    /*****************************slave********************************************/
    /**
     * 2013-11-15 
     * @param keyName 主键名字
     * @param key 主键值
     * @return
     */
    public E get(String keyName, Object key) {
        return findOne(String.format(GETS, tableName, keyName), key, 0, 1);
    }

    public E findOne(String sql, Object... args) {
        return findOne(SLAVE_SOURCE, sql, args);
    }

    public List<E> find(String sql, Object... args) {
        return find(SLAVE_SOURCE, sql, args);
    }

    public List<E> query(int offset, int limit) {
        return find("select * from " + tableName + " limit ?,?", offset, limit);
    }

    public List<E> query(String keyName, Object key, int offset, int limit) {
        return find(String.format(GETS, tableName, keyName), key, offset, limit);
    }

    /**
     * 得到int 值
     * @param source 数据库源
     * @param sql
     * @param args 参数
     * @return
     */
    public int findForInt(String sql, Object... args) {
        return findForInt(SLAVE_SOURCE, sql, args);
    }

    public Map<String, Object> queryForMap(String tableName, String keyName, Object key) {
        return findForMap(String.format(GETS, tableName, keyName), key, 0, 1);

    }

    /**
     * 查找一条记录
     * @param source 数据库源
     * @param sql
     * @param args 参数
     * @return
     */
    public Map<String, Object> findForMap(String sql, Object... args) {
        return findForMap(SLAVE_SOURCE, sql, args);

    }

    /**
     * 查找多条记录
     * @param source 数据库源
     * @param sql
     * @param args 参数
     * @return
     */
    public List<Map<String, Object>> findForList(String sql, Object... args) {
        return findForList(SLAVE_SOURCE, sql, args);
    }

    /**
     *  得到某列的值
     * @param <T>
     * @param source 数据库源
     * @param sql
     * @param requiredType
     * @param args 参数
     * @return
     */
    public <T> T findColumValue(String sql, Class<T> requiredType, Object... args) {
        return findColumValue(SLAVE_SOURCE, sql, requiredType, args);
    }

    public <T> List<T> findColumValues(String key, Class<T> requiredType, Object... args) {
        return findColumValues(SLAVE_SOURCE, key, requiredType, args);
    }

    public List<E> sFind(String sql, SqlParameterSource args) {
        return sFind(SLAVE_SOURCE, sql, args);
    }

    public List<E> sFind(String sql, Collection<?> ids) {
        final MapSqlParameterSource parameters = new MapSqlParameterSource();
        parameters.addValue("ids", ids);
        return sFind(SLAVE_SOURCE, sql, parameters);
    }

    /**
     * 
     * 2014-2-19 
     * @param tableName  表名，默认pojo类名
     * @return 总条数
     */
    public int count(String tableName) {
        if (DataUtil.isEmpty(tableName))
            tableName = this.tableName;
        return findForInt("select count(1) from " + tableName);
    }

    /**
     * 
     * 2014-2-19 
     * @param tableName 表名，默认pojo类名
     * @param keyName 查询字段
     * @param key    查询条件
     * @return 总条数
     */
    public int count(String tableName, String keyName, Object key) {
        if (DataUtil.isEmpty(tableName))
            tableName = this.tableName;
        return super.findForInt(SLAVE_SOURCE, "select count(1) from " + tableName + " where " + keyName + "=?", key);
    }
}
